library ieee;
 use ieee.std_logic_1164.all;
 use ieee.std_logic_unsigned.all;

library work;
    use work.router_pack.all;
    use work.env_pack.all;
    
-------------------------------------------------------------------------

entity environment is
end environment;

-------------------------------------------------------------------------

architecture environment_arch of environment is

-- Environment Components --

component module
port(
   -- General Signals: --
   RESET   		: in std_logic;
   MODULE_ID	: in std_logic_vector(2*e_coord_position_width_c-1 downto 0);
   
   -- Input Port i/f: --
   RI      : in std_logic;
   AI      : out std_logic;
   DI      : in std_logic_vector(flit_size_c-1 downto 0);
       
   -- Output Port i/f: --
   RO      : out std_logic;
   AO      : in std_logic;
   DO      : out std_logic_vector(flit_size_c-1 downto 0);
   
   -- Environment Settings --
    WORKLOAD          : in std_logic_vector(e_workload_width_c-1 downto 0);
    MAX_VC            : in std_logic_vector(vc_width-1 downto 0);
    MAX_SL            : in std_logic_vector(msl_ind_width-1 downto 0);
    MAX_PACKET_SIZE   : in std_logic_vector(e_packet_size_width_c-1 downto 0);
    MIN_PACKET_SIZE   : in std_logic_vector(e_packet_size_width_c-1 downto 0)
);    
end component;    

component msl_router is
port(
       -- General Signlas: --
       RESET           : in  std_logic; 
       
       -- Input Ports i/f: --
       RI              : in  std_logic_vector(num_of_ports_con downto 0);
       AI              : out std_logic_vector(num_of_ports_con downto 0);
       --DI              : in  msl_router_mult_ports_data_bus_type;
       DI              : in  std_logic_vector(64 downto 0);
       
       -- Output Ports i/f: --
       RO              : out std_logic_vector(num_of_ports_con downto 0);
       AO              : in  std_logic_vector(num_of_ports_con downto 0);
       --DO              : out msl_router_mult_ports_data_bus_type
       DO              : out std_logic_vector(64 downto 0)
);    
end component;

-- Internal Signals --

signal       reset           :   std_logic; 

type r_ctl_arr is array (e_routers_per_raw_count_c-1 downto 0, e_routers_per_raw_count_c-1 downto 0) of std_logic_vector(num_of_ports_con downto 0);
type r_data_arr is array (e_routers_per_raw_count_c-1 downto 0, e_routers_per_raw_count_c-1 downto 0) of std_logic_vector(64 downto 0);
type m_ctl_arr is array (e_routers_per_raw_count_c-1 downto 0, e_routers_per_raw_count_c-1 downto 0) of std_logic;
type m_data_arr is array (e_routers_per_raw_count_c-1 downto 0, e_routers_per_raw_count_c-1 downto 0) of std_logic_vector(12 downto 0);


-- Router Ports --
signal ri_r   : r_ctl_arr;
signal ai_r   : r_ctl_arr;
signal di_r   : r_data_arr;
       
signal ro_r   : r_ctl_arr;
signal ao_r   : r_ctl_arr;
signal do_r   : r_data_arr;


-- Module Ports --
signal ri_m     : m_ctl_arr;
signal ai_m     : m_ctl_arr;
signal di_m     : m_data_arr;

signal ro_m     : m_ctl_arr;
signal ao_m     : m_ctl_arr;
signal do_m     : m_data_arr;


signal MOD_ID_M00   : std_logic_vector(2*e_coord_position_width_c-1 downto 0);
signal MOD_ID_M01   : std_logic_vector(2*e_coord_position_width_c-1 downto 0);
signal MOD_ID_M10   : std_logic_vector(2*e_coord_position_width_c-1 downto 0);
signal MOD_ID_M11   : std_logic_vector(2*e_coord_position_width_c-1 downto 0);

signal env_workload          : std_logic_vector(e_workload_width_c-1 downto 0);
signal env_max_vc            : std_logic_vector(vc_width-1 downto 0);
signal env_max_sl            : std_logic_vector(msl_ind_width-1 downto 0);
signal env_max_packet_size   : std_logic_vector(e_packet_size_width_c-1 downto 0);
signal env_min_packet_size   : std_logic_vector(e_packet_size_width_c-1 downto 0);


-- Environment Implementation --

begin
    
    -- Environment configuration --
    
    env_workload <= "0101";          -- 5 (50%)
    env_max_vc <= "1";               -- 1
    env_max_sl <= "11";              -- 3
    env_max_packet_size <= "1111";   -- 15
    env_min_packet_size <= "0010";   -- 2
    
    -- Environment interconnectivity --
    
   vertical_gen: for i in 0 to e_routers_per_raw_count_c-1 generate
   horizontal_gen: for j in 0 to e_routers_per_raw_count_c-1 generate
   
   data_aliasing: for p in 0 to num_of_ports_con generate
      alias di_rp(i,j)(p)   : m_data_arr is di_r(i,j)((p+1)*13-1 downto p*13);
      alias do_rp(i,j)(p)   : m_data_arr is do_r(i,j)((p+1)*13-1 downto p*13);   end generate data_aliasing;
   
   begin
       
      u_msl_router: msl_router
      port map(
         RESET           => reset, 
       
         RI              => ri_r(i)(j),
         AI              => ai_r(i)(j),
         DI              => di_r(i)(j),
       
         RO              => ro_r(i)(j),
         AO              => ao_r(i)(j),
         DO              => do_r(i)(j)
      );

      u_module: module
      port map(
         RESET   => reset,
         MODULE_ID =>  MOD_ID_M00,   --FIXME: create a function
       
         RI      => ri_m(i)(j),
         AI      => ai_m(i)(j),
         DI      => di_m(i)(j),
       
         RO      => ro_m(i)(j),
         AO      => ao_m(i)(j),
         DO      => do_m(i)(j),
       
         WORKLOAD        => env_workload,
         MAX_VC          => env_max_vc,
         MAX_SL          => env_max_sl,
         MAX_PACKET_SIZE => env_max_packet_size,
         MIN_PACKET_SIZE => env_min_packet_size
      );
      
      
      -- Router/Module Connections --
      ri_r(i)(j)(e_module_port_c)   <= ri_m(i)(j);
      ai_m(i)(j)                    <= ai_r(i)(j)(e_module_port_c);
      di_rp(i)(j)(e_module_port_c)  <= di_m(i)(j);
   
      ro_m(i)(j)                    <= ro_r(i)(j)(e_module_port_c);
      ao_r(i)(j)(e_module_port_c)   <= ao_m(i)(j);
      do_m(i)(j)                    <= do_rp(i)(j)(e_module_port_c);
      
      
      -- Inter Router Connections --

      top_connect: if (i > 0) generate 
      begin
         ri_r(i)(j)(e_top_port_c)     <= ro_r(i-1)(j)(e_bottom_port_c);
         di_rp(i)(j)(e_top_port_c)    <= do_rp(i-1)(j)(e_bottom_port_c);
         ao_r(i)(j)(e_top_port_c)     <= ai_r(i-1)(j)(e_bottom_port_c);
      end generate top_connect;
      
      right_connect: if (j < e_routers_per_raw_count_c-1) generate
      begin
         ri_r(i)(j)(e_right_port_c)   <= ro_r(i)(j+1)(e_left_port_c);
         di_rp(i)(j)(e_right_port_c)  <= do_rp(i)(j+1)(e_left_port_c);
         ao_r(i)(j)(e_right_port_c)   <= ai_r(i)(j+1)(e_left_port_c);
      end generate right_connect;
      
      bottom_connect: if (i < e_routers_per_raw_count_c-1) generate
      begin
         ri_r(i)(j)(e_bottom_port_c)  <= ro_r(i+1)(j)(e_top_port_c);
         di_rp(i)(j)(e_bottom_port_c) <= do_rp(i+1)(j)(e_top_port_c);
         ao_r(i)(j)(e_bottom_port_c)  <= ai_r(i+1)(j)(e_top_port_c);
      end generate bottom_connect;
      
      left_connect: if (j > 0) generate 
      begin
         ri_r(i)(j)(e_left_port_c)    <= ro_r(i)(j-1)(e_right_port_c);
         di_rp(i)(j)(e_left_port_c)   <= do_rp(i)(j-1)(e_right_port_c);
         ao_r(i)(j)(e_left_port_c)    <= ai_r(i)(j-1)(e_right_port_c);
      end generate left_connect;
      
   end generate horizontal_gen;
   end generate vertical_gen;
   
   -- Constant values of Module ID's
    MOD_ID_M00 <= "00";
    MOD_ID_M01 <= "01";
    MOD_ID_M10 <= "10";
    MOD_ID_M11 <= "11";
    
end environment_arch;


